#include <string>
#include <memory> // std::auto_ptr
#include <cstdlib> // std::exit
#include <iostream>
#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include "../user/test/mysql_test/user-odb.hxx"
#include "logger.hpp"

// 实现的功能:
// 用户注册, 用户登录, 验证码获取, 手机号注册, 手机号登录, 获取用户信息, 用户信息修改, 用户信息新增, 
// 通过昵称获取用户信息, 通过手机号获取用户信息, 通过用户ID获取用户信息, 通过多个用户ID获取多个用户信息, 

namespace wufan_im{

// 此次封装的目的: 1.简洁代码: 只用提供参数, 就可以构造出我们的目标对象, 不用写中间的代码
//                2.解耦合: 只用修改这个工厂, 不用到处修改里面的代码
class ODBFactory{
    public:
        static std::shared_ptr<odb::core::database> create(const std::string& user, const std::string& pswd,
            const std::string& host, const std::string& db, const std::string& cset, int port, int conn_pool_count){
            std::unique_ptr<odb::mysql::connection_pool_factory> cpf(new odb::mysql::connection_pool_factory(conn_pool_count, 0));
            auto res = std::make_shared<odb::mysql::database>(user, pswd, db, host, port, "", cset, 0, std::move(cpf));
            return res;
        }
};

//对用户表的操作进行一个封装
class UserTable{
    public:
        using ptr = std::shared_ptr<UserTable>;
        UserTable(const std::shared_ptr<odb::core::database>& db):_db(db){}
        bool insert(const std::shared_ptr<User>& user) {
            try{    //操作的时候, 可能抛异常, 就需要捕捉异常, 否则会程序崩溃
                // 获取事务对象, 开启事务
                odb::transaction trans(_db->begin());
                _db->persist(*user);
                // 提交事务
                trans.commit();
            }catch (std::exception& e) {
                LOG_ERROR("插入用户数据失败:{}", e.what());
                return false;
            }
            return true;
        }
        bool update(const std::shared_ptr<User>& user) {
            try{
                // 获取事务对象开启事务
                odb::transaction trans(_db->begin());
                _db->update(*user);
                // 提交事务
                trans.commit();
            } catch (std::exception& e) {
                LOG_ERROR("更新用户数据失败:{}", e.what());
                return false;
            }
            return true;
        }
        std::shared_ptr<User> select_by_nickname(const std::string& nickname) {
            std::shared_ptr<User> res;
            try {
                // 获取事务对象开启事务
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;      //这个类是过滤条件类
                typedef odb::result<User> result;    //用于存储查询结果的容器类
                res.reset(_db->query_one<User>(query::nickname == nickname));
                // 提交事务
                trans.commit();
            } catch (std::exception& e) {
                LOG_ERROR("通过昵称查询用户数据失败:{}", e.what());
            }
            return res;
        }
        std::shared_ptr<User> select_by_phone(const std::string& phone) {
            std::shared_ptr<User> res;
            try {
                // 获取事务对象开启事务
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;      //这个类是过滤条件类
                typedef odb::result<User> result;    //用于存储查询结果的容器类
                res.reset(_db->query_one<User>(query::phone == phone));
                // 提交事务
                trans.commit();
            } catch (std::exception& e) {
                LOG_ERROR("通过手机号查询用户数据失败:{}", e.what());
            }
            return res;
        }
        std::shared_ptr<User> select_by_id(const std::string& user_id) {
            std::shared_ptr<User> res;
            try {
                // 获取事务对象开启事务
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;      //这个类是过滤条件类
                typedef odb::result<User> result;    //用于存储查询结果的容器类
                res.reset(_db->query_one<User>(query::user_id == user_id));
                // 提交事务
                trans.commit();
            } catch (std::exception& e) {
                LOG_ERROR("通过用户ID查询用户数据失败:{}", e.what());
            }
            return res;
        }
        std::vector<User> select_multi_users(const std::vector<std::string>& id_list) {
            std::vector<User> res;
            try {
                // 获取事务对象开启事务
                odb::transaction trans(_db->begin());
                typedef odb::query<User> query;      //这个类是过滤条件类
                typedef odb::result<User> result;    //用于存储查询结果的容器类
                std::string condition;
                condition += "user_id in (";
                for (auto& e : id_list) {
                    condition += "'" + e + "',";
                }
                condition.pop_back();
                condition += ")";
                auto r = _db->query<User>(condition);
                for (auto it = r.begin(); it != r.end(); ++it) {
                    res.push_back(*it);
                }
                // 提交事务
                trans.commit();
            } catch (std::exception& e) {
                LOG_ERROR("通过用户ID查询用户数据失败:{}", e.what());
            }
            return res;
        }
    private:
        std::shared_ptr<odb::core::database> _db;
};

}